const fs = require('fs')
const path = require("path")
const exec = require('child_process').exec
const multiparty = require('multiparty')  // 处理表单提交的数据
const crypto = require('crypto')

const {UPLOADPATH,IPFS_WEB_URL} = require('../config')

/**
 * 请求处理成功时响应
 * @param {*} res 响应对象
 * @param {*} data 返回数据
 * @param {*} message  返回信息描述
 */
function backSuc(res,data='',message='请求处理成功',code=200){
    res.json({code,data,message})
}

/**
 * 请求处理失败时响应
 * @param {*} res 响应对象
 * @param {*} message  返回信息描述
 * @param {*} data  返回数据
 */
function backErr(res,message='请求处理失败',code=1000,data=''){
    res.json({code,data,message})
}

/**
 * 列分页请求数据成功响应
 * @param {*} res 响应对象
 * @param {*} data 返回数据
 * @param {*} total 数据总数
 * @param {*} pageIndex  当前页
 * @param {*} message 返回信息描述
 * @param {*} code 代码
 */
function backPage(res,data='',total,pageIndex,message='请求处理成功',code=200){
    res.json({code,data,total,pageIndex,message})
}

/**
 * 把图片base64编码转化为图片
 * @param {*} base64 编码
 * @param {*} suffix 生成图片后缀名
 */
function base64ToImg(base64,suffix='jpg'){
　　return new Promise((resolve,reject) =>{
        let fileName = Date.now() +'.'+suffix
        let filePath = path.join(__dirname,'../',UPLOADPATH+fileName)//创建一个图片路径
       // console.log("创建的路径：",filePath)
        let data = base64.replace(/^data:image\/\w+;base64,/, "");//去掉图片base64码前面部分data:image/png;base64
        let dataBuffer = Buffer.from(data, 'base64'); //把base64码转成buffer对象，
        //console.log('dataBuffer是否是Buffer对象：'+Buffer.isBuffer(dataBuffer));
        fs.writeFile(filePath,dataBuffer,async (err)=>{//用fs写入文件
            if(err){
                console.log('写入失败！');
                resolve(false)
            }else{
                console.log('写入成功！开始上传到ipfs');
                const ipfs_add_cmd = `ipfs add ${filePath}`
                const result = await doCmd(ipfs_add_cmd)
                if(result){
                    const arr = result.split(/[\s\n]/)  // 以空格和换行进行分割获取
                    const hash = arr[1]  // 该文件对应的hash值
                    resolve(IPFS_WEB_URL+hash)  // 返回hash值
                }else{
                    console.log(`${filePath}上传ipfs失败`)
                    resolve(false)
                }
                // 上传ipfs成功后删除该文件
                fs.unlink(filePath, function(err){
                    if(err){
                         throw err;
                    }
               })
                
            }
        })
    })
}

/**
 * 执行cmd命令
 * @param {*} cmd 需要执行的命令字符串
 */
function doCmd(cmd){
    return new Promise((resolve,reject)=>{
        exec(cmd, (error, stdout, stderr) =>{
            if(error){
                resolve(false)
            }
            else{
                resolve(stdout) 
            }
        });
    })
}

/**
 * 
 * @param {*} path 文件路径
 * @param {*} removeFileFlag 上传成功后是否删除原文件
 */
function ipfsAddFile(path,removeFileFlag=true){
    return new Promise(async (resolve,reject) => {
        const ipfs_add_cmd = `ipfs add ${path}`
        const result = await doCmd(ipfs_add_cmd)
        if(result){
            const arr = result.split(/[\s\n]/)  // 以空格和换行进行分割获取
            const hash = arr[1]  // 该文件对应的hash值
            resolve(IPFS_WEB_URL+hash)  // 返回hash值
        }else{
            console.log(`${path}上传ipfs失败`)
            resolve(false)
        }
        if(removeFileFlag){
            // 上传ipfs成功后删除该文件
            fs.unlink(path, function(err){
                if(err){
                    throw err;
                }
            })
        }
    })
} 

/**
 * 合并对象，只保留相同属性
 * @param {Object} target  目标对象
 * @param {Object} newObj  需要替换目标对象值的对象
 */
function mergeObject(target,newObj){
	for(let key in target){
		target[key] = newObj[key] || ''
	}
	return target
}

/**
 * 过滤对象中的属性值不存在的属性
 * @param {*} target 需要过滤的对象
 * @param {*} excludes 不需要过滤的属性数组
 */
function fliterObject(target,excludes=[]){
    let newObj = {}
    for(let key in target){
        if(excludes.length>0 && excludes.indexOf(key)>-1){ 
            newObj[key] = target[key]
        }else{
            if(target[key]===0 || target[key]==='0'){  // js中  ''==0  结果为true
                newObj[key] = target[key]
            }else if(target[key] && target[key]!='null'){
                newObj[key] = target[key]
            }
        }
    }
    return newObj
}



/**
 * 
 * @param {*} n 生成n位数的随机码
 */
function getRandom(n){
    var code = "";
　　for(var i=0;i<n;i++){
　　　　var radom = Math.floor(Math.random()*10);
　　　　code += radom;
　　}
　　return code
}

/**
 * 验证码手机号是否正确
 * @param {*} phones 手机号
 */
function checkMobile(phones){
    var myreg = /^[1][3,4,5,7,8,9][0-9]{9}$/;
    if (!myreg.test(phones)) {
      return false;
    } else {
      return true;
    }
}

/**
 * 获取设备类型
 * @param {*} req 客户端请求对象
 */
function getDevice(req){
    var deviceAgent = req.headers["user-agent"].toLowerCase();
    var agentID = deviceAgent.match(/(dart|iphone|ipod|ipad|android)/);
    if(agentID){
        return 'app'
    }else{
        return 'pc'
    }
}


/**
 * 
 * @param {*} req 请求对象
 * @param {*} proxyType 
 * @returns 
 */
function getClientIp(req, proxyType) {
    let ip = req.connection.remoteAddress || req.socket.remoteAddress || (req.connection.socket ? req.connection.socket.remoteAddress : null);
    // 如果使用了nginx代理
    if (proxyType === 'nginx') {
        // headers上的信息容易被伪造,但是我不care,自有办法过滤,例如'x-nginx-proxy'和'x-real-ip'我在nginx配置里做了一层拦截把他们设置成了'true'和真实ip,所以不用担心被伪造
        // 如果没用代理的话,我直接通过req.connection.remoteAddress获取到的也是真实ip,所以我不care
        ip = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || ip;
    }
    const ipArr = ip.split(',');
    // 如果使用了nginx代理,如果没配置'x-real-ip'只配置了'x-forwarded-for'为$proxy_add_x_forwarded_for,如果客户端也设置了'x-forwarded-for'进行伪造ip
    // 则req.headers['x-forwarded-for']的格式为ip1,ip2只有最后一个才是真实的ip
    if (proxyType === 'nginx') {
        ip = ipArr[ipArr.length - 1];
    }
    if (ip.indexOf('::ffff:') !== -1) {
        ip = ip.substring(7);
    }
    return ip;
}



/**
 * 对字符串进行加密，
 * @param {*} str 要加密的字符串
 * @param {*} key 加密key
 * @param {*} type 加密类型，默认HMAC-SHA1
 * @returns 
 */
function encryption(str,key,type='HMAC-SHA1'){
    let hash = ''
    if(type=='HMAC-SHA1'){
        hash = crypto.createHmac('sha1',key).update(str).digest().toString('base64');
    }else if(type=='HMAC-SHA256'){
        hash = crypto.createHmac('SHA256', key).update(str).digest('hex') 
    }
    return hash
}

/**
 * 在文件末尾添加内容，没有文件时，则创建文件
 * @param {*} path 文件目录（包括文件名）
 * @param {*} con 添加的内容
 */
const appendConToFile = (path,con)=>{
    return new Promise((resolve,reject) =>{
        fs.open(path,async (err,data)=>{
            if(err){  // 说明文件不存在
                // 写入文件，文件不存在时，创建文件
                fs.writeFile(path, con, function (err) {
                    if (err) {
                        resolve(false)
                    }else{
                        resolve(true) 
                    }
                });
            }else{  // 文件存在
                fs.appendFile(path,con , (err)  => {
                    if (err) {
                        resolve(false)
                    }else{
                        resolve(true) 
                    }
                });
            }
        })
    })
}

/**
 * 解析参数，把分页参数放在一个对象中，其他单独放在另外一个对象中
 * @param {*} obj // 需要解析的参数对象
 * @returns 
 */
function resolveParams(obj){
    let params = {},page = {}
    for(let key in obj){
        if(key== 'pageIndex' || key== 'pageSize'){
            page[key] = obj[key]
        }else if(obj[key]===0 || obj[key]==='0'){  // js中  ''==0  结果为true
            params[key] = obj[key]
        }else if(obj[key] && obj[key]!='null'){
            params[key] = obj[key]
        }
    }
    return {params,page}
}
// 计价单位换算
const getUnitVal = (str)=>{
    switch (str) {
        case "平方":
            return 1;
        case "个":
            return 2;
        case "扇":
            return 3;
        case "套":
            return 4;
        case "米":
            return 5;
        case "支":
            return 7;
        case "把":
            return 8;
        case "片":
            return 9;
        case "粒":
            return 10;
        case "件":
            return 11;
        default:
            return "";
    }
}



module.exports = {
    backSuc,
    backErr,
    backPage,
    base64ToImg,
    getRandom,
    ipfsAddFile,
    checkMobile,
    mergeObject,
    fliterObject,
    doCmd,
    getDevice,
    getClientIp,
    encryption,
    appendConToFile,
    resolveParams,
    getUnitVal
}